package com.krtech.wecard.module.mayi.controller;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.krtech.wecard.config.WecardRedisTemplate;
import com.krtech.wecard.framework.exception.BusinessException;
import com.krtech.wecard.framework.model.CommRes;
import com.krtech.wecard.framework.security.Inner;
import com.krtech.wecard.module.mayi.MayiPayEnums;
import com.krtech.wecard.module.mayi.entity.*;
import com.krtech.wecard.module.mayi.mapper.MayiPayListMapper;
import com.krtech.wecard.module.mayi.service.*;
import com.krtech.wecard.module.pay.enums.PayEnums;
import com.krtech.wecard.module.sys.entity.SysKeyValue;
import com.krtech.wecard.module.sys.service.SysKeyValueService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/mayiPay")
@Slf4j
@Api(value = "蚂蚁阅读量中控管理")
public class MayiPayListController {

    @Autowired
    private MayiPayListService mayiPayListService;

    @Autowired
    private MayiCdkManageService cdkManageService;

    @Autowired
    private MayiMachineManageService machineManageService;

    @Autowired
    private MayiPayListMapper payListMapper;

    @Autowired
    private SysKeyValueService keyValueService;

    @Autowired
    private WecardRedisTemplate redisTemplate;

    @Autowired
    private MayiCommentSayService commentSayService;


    //页面查询列表（正在执行的和等待列表）
    @GetMapping("/list")
    @ApiOperation(value = "list")
    @Inner(value = false)
    public List<MayiPayListSimple> list(String phone) {
        List<MayiPayList> list = mayiPayListService.list(new QueryWrapper<MayiPayList>()
                .in(MayiPayList.COL_STATUS, MayiPayEnums.PAY_AND_NOT_RUN, MayiPayEnums.PAY_AND_RUNING).orderByDesc(MayiPayList.COL_STATUS,MayiPayList.COL_ID));

        //list给模糊了
        List<MayiPayListSimple> simpleList = list.stream().map(pay -> {
            MayiPayListSimple simple = new MayiPayListSimple();
//            simple.setFkUserCode(pay.getFkUserCode());
            simple.setFkUserCode("***********");
            simple.setStatus(pay.getStatus());
            if (StrUtil.isNotEmpty(phone)){
                if (pay.getFkUserCode().equals(phone)){
                    simple.setHasSelf(1);
                }else {
                    simple.setHasSelf(0);
                }
            }else {
                simple.setHasSelf(0);
            }

            return simple;
        }).collect(Collectors.toList());

        return simpleList;
    }

    //手动添加某个订单
    @PostMapping("/backAdd")
    @ApiOperation(value = "手动添加某个订单")
    public boolean backAdd(@RequestBody MayiPayListVo addMailPay) {
        return mayiPayListService.backAdd(addMailPay);
    }

    @PostMapping("/batchBackAdd")
    @ApiOperation(value = "手动批量添加某个订单")
    public boolean batchBackAdd(@RequestBody MayiPayListVo addMailPay) {
        return mayiPayListService.batchBackAdd(addMailPay);
    }

    @PostMapping("/backDianzanAdd")
    @ApiOperation(value = "手动添加点赞订单")
    public boolean backDianzanAdd(@RequestBody MayiPayListVo addMailPay) {
        return mayiPayListService.backDianzanAdd(addMailPay);
    }

    @PostMapping("/backgroudDianzanAdd")
    @ApiOperation(value = "后台手动添加点赞订单")
    public boolean backgroudDianzanAdd(@RequestBody MayiPayListVo addMailPay) {
        return mayiPayListService.backgroudDianzanAdd(addMailPay);
    }

    @PostMapping("/backGroudCommentAdd")
    @ApiOperation(value = "后台手动添加评论订单")
    public boolean backGroudCommentAdd(@RequestBody MayiPayListVo addMailPay) {
        return mayiPayListService.backGroudCommentAdd(addMailPay);
    }


    //脚本访问地址1.获取当前该执行（如果没有正在执行，就给一个该执行的，如果有正在执行的，就把这个正在执行的给）
    @GetMapping("/getcurrent")
    @ApiOperation(value = "获得当前该执行的")
    @Inner(value = false)
    public MayiPayList getcurrent(String machineId) {
        //保活
        mayiPayListService.keepAlive(machineId,null);
        //获得任务
        return mayiPayListService.getTaskByMachineId(machineId);
    }

    //脚本访问地址2.通知获取到了，开始执行
    @GetMapping("/run")
    @ApiOperation(value = "通知某个开始执行了")
    @Inner(value = false)
    public boolean run(String orderNumber,String machineId) {
        MayiPayList mayiPayList = mayiPayListService.getOne(new QueryWrapper<MayiPayList>().eq(MayiPayList.COL_ORDER_NO, orderNumber));
        if (mayiPayList == null){
            throw new BusinessException("回调异常，没有这个订单，请联系管理员");
        }
        //判断是否有开始时间
        if (mayiPayList.getStartTime() == null){
            mayiPayList.setStartTime(new Date());
        }

        //更新其已经完成支付的状态
        mayiPayList.setStatus(MayiPayEnums.PAY_AND_RUNING);
        return mayiPayListService.updateById(mayiPayList);
    }

    @GetMapping("/course")
    @ApiOperation(value = "过程中")
    @Inner(value = false)
    @Transactional(rollbackFor = Exception.class)
    public boolean course(String orderNumber,String machineId) {

//        先调用自增，再查，合理
        payListMapper.incre(orderNumber);


        MayiPayList mayiPayList = mayiPayListService.getOne(new QueryWrapper<MayiPayList>()
                .eq(MayiPayList.COL_ORDER_NO, orderNumber));

        if (mayiPayList == null){
            throw new BusinessException("订单:"+orderNumber+"为空，请联系管理员");
        }

        //每次心跳，意味着，都要将数量+1 ,
        mayiPayListService.keepAlive(machineId,orderNumber);

        //移除sexNx的锁
        Integer machineCount = mayiPayListService.machineList(machineId);
        redisTemplate.del("lockSort:" + machineCount);

        //如果通过course了，说明已经过掉了上面的文章链接失效的限制，将其状态改为2,并且
//        if (mayiPayList.getReachCount() < mayiPayList.getRealGoalCount()){
//            //说明还没跑完
//            mayiPayList.setStatus(2);
//            mayiPayListService.updateById(mayiPayList);
//        }

        //判断这个任务的状态 ,是3，4，5的时候都停止
        if (mayiPayList.getStatus().equals(MayiPayEnums.PAY_AND_RUN_OVER) ||
                mayiPayList.getStatus().equals(MayiPayEnums.PAY_AND_RUN_EXCEPTION)||
                        mayiPayList.getStatus().equals(MayiPayEnums.MYSELF_STOP)){
            return false;
        }

        //将数据和last
        // 我计算他的目标数量 目标 - 当前，如果大于0，就返回true
        Integer reachCount = mayiPayList.getReachCount();
        Integer goalCount = mayiPayList.getRealGoalCount();
        if ((goalCount - reachCount) <= 0){
            //说明结束了
            return false;
        }else {
            return true;
        }
    }

    //脚本访问地址3.通知结束了
    @GetMapping("/over")
    @ApiOperation(value = "通知某个开始结束了")
    @Inner(value = false)
    public boolean over(String orderNumber,String machineId) {
        MayiPayList mayiPayList = mayiPayListService.getOne(new QueryWrapper<MayiPayList>().eq(MayiPayList.COL_ORDER_NO, orderNumber));
        if (mayiPayList == null){
            throw new BusinessException("回调异常，没有这个订单，请联系管理员");
        }

        //判断是否有开始时间
        if (mayiPayList.getEndTime() == null){
            mayiPayList.setEndTime(new Date());
        }


        //更新其已经完成支付的状态
        if ((mayiPayList.getStatus() == 1) || (mayiPayList.getStatus() == 2)){
            mayiPayList.setStatus(MayiPayEnums.PAY_AND_RUN_OVER);
            return mayiPayListService.updateById(mayiPayList);
        }
        return true;
    }

    @Autowired
    private MayiDianzanLogService dianzanLogService;

    @GetMapping("/dianzanOver")
    @ApiOperation(value = "通知某台机子点完赞了")
    @Inner(value = false)
    public boolean dianzanOver(String orderNumber,String machineId) {
        return mayiPayListService.dianzanOver(orderNumber,machineId);
    }

    @GetMapping("/exception")
    @ApiOperation(value = "通知某个任务异常了")
    @Inner(value = false)
    public boolean exception(String orderNumber,String machineId) {
        return mayiPayListService.exception(orderNumber,machineId);
    }

    @GetMapping("/getGoal")
    @ApiOperation(value = "获得目标数量")
    @Inner(value = false)
    public Integer getGoal(String orderNumber,Integer current) {

        MayiPayList mayiPayList = mayiPayListService.getOne(new QueryWrapper<MayiPayList>()
                .eq(MayiPayList.COL_ORDER_NO, orderNumber));

        if (mayiPayList == null){
            throw new BusinessException("订单:"+orderNumber+"为空，请联系管理员");
        }

        if (mayiPayList.getReachCount() != null){
            return mayiPayList.getReachCount();
        }

        Integer reachCount = current + mayiPayList.getGoalCount();

        //保存
        mayiPayList.setReachCount(reachCount);
        mayiPayListService.updateById(mayiPayList);

        return reachCount;
    }




    //拉去支付
    @PostMapping("/storePay")
    @ApiOperation(value = "商品支付")
    public CommRes storePay(@RequestBody MayiPayEntity mayiPayEntity) {
        return mayiPayListService.storePay(mayiPayEntity);
    }

    //回调支付
    @PostMapping("/notify")
    public String notify(@RequestBody String xmlData) throws Exception {
        return mayiPayListService.notify(xmlData);
    }

    @GetMapping("/getTaskRemainingTime")
    @ApiOperation(value = "获得当前任务剩余时间")
    @Inner(value = false)
    public Integer getTaskRemainingTime() {
        //拿到最近的完成的一个任务，通过max的overtime获得
        MayiPayList maxOverTime = payListMapper.getMaxOverTime();
        //根据开始时间 结束时间 和量 算出一个量需要多久

        //获得秒数
        long between = DateUtil.between(maxOverTime.getStartTime(), maxOverTime.getEndTime(), DateUnit.SECOND);
        //用秒除以量,得到一个量需要多少秒
        BigDecimal betweenBig = new BigDecimal(between);
        BigDecimal realGoalBig = new BigDecimal(maxOverTime.getRealGoalCount());
        BigDecimal resultUnit = betweenBig.divide(realGoalBig,2,BigDecimal.ROUND_HALF_UP);

        //计算当前的量
        List<MayiPayList> waitCountList = payListMapper.getWaitCountList();

        long realGoalCountSum = waitCountList.stream().mapToLong(MayiPayList::getRealGoalCount).sum();

        long reachCountSum = waitCountList.stream().mapToLong(MayiPayList::getReachCount).sum();

        long waitCount = realGoalCountSum - reachCountSum;

        BigDecimal result = resultUnit.multiply(new BigDecimal(waitCount));
        return result.intValue();

    }


//    @GetMapping("/machineList")
//    @ApiOperation(value = "获得分组")
//    @Inner(value = false)
    public ArrayList<List<MayiMachineManage>> machineList(){
        ArrayList<List<MayiMachineManage>> resultList = new ArrayList<>();
        //考虑做成map，键是机器码，值是第几个分组

        SysKeyValue machineListCount = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_KEY, MayiPayEnums.MACHINE_LIST_COUNT));

        Integer machineListCountSysValue = Integer.parseInt(machineListCount.getSysValue());

        //看有多少台机器
        List<MayiMachineManage> allMachineList = machineManageService.list();

        int machineCount = allMachineList.size();

        Integer pageCount = machineCount / machineListCountSysValue;


        for (int i = 1;i<=machineListCountSysValue;i++){
            Page<MayiMachineManage> page = new Page<MayiMachineManage>();

            page.setCurrent(i);
            page.setSize(pageCount);

            Page<MayiMachineManage> machinePage = machineManageService.page(page);
            List<MayiMachineManage> machineList = machinePage.getRecords();


            allMachineList = allMachineList.stream().filter(allOne->{
                return !machineList.stream().map(MayiMachineManage::getId).collect(Collectors.toList()).contains(allOne.getId());
            }).collect(Collectors.toList());

            if (i == machineListCountSysValue){
                //说明是最后一次了，就把allMachineList添加进入machineList
                machineList.addAll(allMachineList);
            }

            //添加进一个分组集合
            resultList.add(machineList);


        }
        return resultList;
    }

    @GetMapping("/getServerAddr")
    @ApiOperation(value = "获得服务器地址")
    @Inner(value = false)
    public CommRes getServerAddr(String machineId) {
        //32980f53f93a779e1ae67f02c68ba6b3c
        //判断是否有这个 machineId，如果没有就先添加一遍
        int hasMachine = machineManageService.count(new QueryWrapper<MayiMachineManage>()
                .eq(MayiMachineManage.COL_MACHINE_ID, machineId));

        if (hasMachine <= 0){
            MayiMachineManage newMachine = new MayiMachineManage();
            newMachine.setMachineId(machineId);
            newMachine.setCreatedTime(new Date());
            newMachine.setLastConnectTime(new Date());
            newMachine.setStatus(1);


            machineManageService.save(newMachine);
        }

        String serverAddr = serverList(machineId);
        //通过算法，判断有
        log.info("机器:"+machineId+"，请求服务器地址，获得:"+serverAddr);
        return CommRes.ok(serverAddr);
//        return CommRes.ok("http://124.223.88.149/mayiread");
    }

    public String serverList(String machineId) {
        //考虑做成map，键是机器码，值是第几个分组
        Map<String, Integer> resultMap = new HashMap<>();



        List<SysKeyValue> valueList = keyValueService.list(new QueryWrapper<SysKeyValue>().eq(SysKeyValue.COL_SYS_KEY, MayiPayEnums.SERVER_ADDR));

        if (valueList.size() <= 0){
            throw new BusinessException("未配置服务器地址");
        }

        if (valueList.size() == 1){
            return valueList.get(0).getSysValue();
        }

        Integer machineListCountSysValue = valueList.size();

        //看有多少台机器
        List<MayiMachineManage> allMachineList = machineManageService
                .list(new QueryWrapper<MayiMachineManage>()
                        .eq(MayiMachineManage.COL_STATUS, 1));

        int machineCount = allMachineList.size();

        Integer pageCount = machineCount / machineListCountSysValue;


        for (int i = 1; i <= machineListCountSysValue; i++) {
            Page<MayiMachineManage> page = new Page<MayiMachineManage>();

            page.setCurrent(i);
            page.setSize(pageCount);

            Page<MayiMachineManage> machinePage = machineManageService.page(page);
            List<MayiMachineManage> machineList = machinePage.getRecords();


            allMachineList = allMachineList.stream().filter(allOne -> {
                return !machineList.stream().map(MayiMachineManage::getId).collect(Collectors.toList()).contains(allOne.getId());
            }).collect(Collectors.toList());

            if (i == machineListCountSysValue) {
                //说明是最后一次了，就把allMachineList添加进入machineList
                machineList.addAll(allMachineList);
            }

            //添加进一个分组集合
//            resultList.add(machineList);

            for (MayiMachineManage machineManage : machineList) {
                resultMap.put(machineManage.getMachineId(), i);

            }
        }
        Integer sequence = resultMap.get(machineId);

        return valueList.get(sequence - 1).getSysValue();
    }


    // 停止任务并返还未执行的
    @GetMapping("/userStopTask")
    @ApiOperation(value = "用户自己停止任务")
    @Inner(value = false)
    public boolean userStopTask(String orderNo) {
        return mayiPayListService.userStopTask(orderNo);
    }

    //置顶任务
    @PostMapping("/pinnedTask")
    @ApiOperation(value = "置顶任务")
    public boolean pinnedTask(@RequestBody PinnedTaskVo pinnedTaskVo) {
        return mayiPayListService.pinnedTask(pinnedTaskVo);
    }

    @GetMapping("/getUrWaitTime")
    @ApiOperation(value = "获得UR等待时间")
    @Inner(value = false)
    public CommRes getUrWaitTime(String machineId) {
        SysKeyValue machineListCount = keyValueService.getOne(new QueryWrapper<SysKeyValue>()
                .eq(SysKeyValue.COL_SYS_KEY, MayiPayEnums.UR_WAIT_TIME));
        //通过算法，判断有
        return CommRes.ok(Integer.parseInt(machineListCount.getSysValue()));
    }

    @GetMapping("/adminStopUr")
    @ApiOperation(value = "管理员手动停止ur")
    public boolean adminStopUr(String orderNo) {
        return mayiPayListService.adminStopUr(orderNo);
    }


    // 修改订单cdk,
    @PostMapping("/editOrderCdkCode")
    @ApiOperation(value = "替换任务cdk编号")
    public boolean editOrderCdkCode(@RequestBody MayiPayList mayiPayList) {
        return mayiPayListService.editOrderCdkCode(mayiPayList);
    }

    //获取随机评论语录
    @GetMapping("/getRandomComment")
    @ApiOperation(value = "获取随机评论语录")
    @Inner(value = false)
    public CommRes getRandomComment() {
        List<MayiCommentSay> commentSayList = commentSayService.list();
        long randomNumber = RandomUtil.randomLong(commentSayList.size());
        MayiCommentSay commentSay = commentSayList.get((int) randomNumber);
        return CommRes.ok(commentSay.getContent());
    }

    //评论结束
    @GetMapping("/commentEnd")
    @ApiOperation(value = "评论结束")
    @Inner(value = false)
    public boolean commentEnd(String orderNumber,String machineId) {
        return mayiPayListService.commentEnd(orderNumber,machineId);
    }
}